package com.zheng.upms.rpc.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.zheng.upms.dao.mapper.*;
import com.zheng.upms.dao.model.*;
import com.zheng.upms.rpc.api.UpmsApiService;
import com.zheng.upms.rpc.api.UpmsRoleOrganizationService;
import com.zheng.upms.rpc.mapper.UpmsApiMapper;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * UpmsApiService实现
 * Created by shuzheng on 2016/01/19.
 */
@Service
@Transactional
public class UpmsApiServiceImpl implements UpmsApiService {

    private static Logger _log = LoggerFactory.getLogger(UpmsApiServiceImpl.class);

    @Autowired
    UpmsUserMapper upmsUserMapper;

    @Autowired
    UpmsApiMapper upmsApiMapper;

    @Autowired
    UpmsRolePermissionMapper upmsRolePermissionMapper;

    @Autowired
    UpmsUserPermissionMapper upmsUserPermissionMapper;

    @Autowired
    UpmsSystemMapper upmsSystemMapper;

    @Autowired
    UpmsOrganizationMapper upmsOrganizationMapper;

    @Autowired
    UpmsLogMapper upmsLogMapper;

    @Autowired
    UpmsRoleOrganizationService upmsRoleOrganizationService;

    @Autowired
    UpmsRoleSystemMapper upmsRoleSystemMapper;

    @Autowired
    UpmsUserSystemMapper userSystemMapper;

    /**
     * 根据用户id获取所拥有的权限
     *
     * @param upmsUserId
     * @return
     */
    @Override
    public List<UpmsPermission> selectUpmsPermissionByUpmsUserId(Integer upmsUserId) {
        // 用户不存在或锁定状态
        UpmsUser upmsUser = upmsUserMapper.selectById(upmsUserId);
        if (null == upmsUser || 1 == upmsUser.getLocked()) {
            _log.info("selectUpmsPermissionByUpmsUserId : upmsUserId={}", upmsUserId);
            return null;
        }
        List<UpmsPermission> upmsPermissions = upmsApiMapper.selectUpmsPermissionByUpmsUserId(upmsUserId);
        return upmsPermissions;
    }

    /**
     * 根据用户id获取所拥有的权限
     *
     * @param upmsUserId
     * @return
     */
    @Override
    @Cacheable(value = "zheng-upms-rpc-service-ehcache", key = "'selectUpmsPermissionByUpmsUserId_' + #upmsUserId")
    public List<UpmsPermission> selectUpmsPermissionByUpmsUserIdByCache(Integer upmsUserId) {
        return selectUpmsPermissionByUpmsUserId(upmsUserId);
    }


    /**
     * 根据用户id获取所属的角色
     *
     * @param upmsUserId
     * @return
     */
    @Override
    public List<UpmsRole> selectUpmsRoleByUpmsUserId(Integer upmsUserId) {
        // 用户不存在或锁定状态
        UpmsUser upmsUser = upmsUserMapper.selectById(upmsUserId);
        if (null == upmsUser || 1 == upmsUser.getLocked()) {
            _log.info("selectUpmsRoleByUpmsUserId : upmsUserId={}", upmsUserId);
            return null;
        }
        List<UpmsRole> upmsRoles = upmsApiMapper.selectUpmsRoleByUpmsUserId(upmsUserId);
        return upmsRoles;
    }

    /**
     * 根据用户id获取所属的角色
     *
     * @param upmsUserId
     * @return
     */
    @Override
    @Cacheable(value = "zheng-upms-rpc-service-ehcache", key = "'selectUpmsRoleByUpmsUserId_' + #upmsUserId")
    public List<UpmsRole> selectUpmsRoleByUpmsUserIdByCache(Integer upmsUserId) {
        return selectUpmsRoleByUpmsUserId(upmsUserId);
    }

    /**
     * 根据角色id获取所拥有的权限
     *
     * @param upmsRoleId
     * @return
     */
    @Override
    public List<UpmsRolePermission> selectUpmsRolePermisstionByUpmsRoleId(Integer upmsRoleId) {
        List<UpmsRolePermission> upmsRolePermissions = upmsRolePermissionMapper
                .selectList(new EntityWrapper<UpmsRolePermission>().eq("role_id", upmsRoleId));
        return upmsRolePermissions;
    }

    /**
     * 根据角色id获取所有系统权限
     *
     * @param upmsRoleId
     * @return
     */
    @Override
    public List<UpmsRoleSystem> selectUpmsRoleSystemByUpmsRoleId(Integer upmsRoleId) {
        return upmsRoleSystemMapper.selectList(new EntityWrapper<UpmsRoleSystem>().eq("role_id", upmsRoleId));
    }

    @Override
    public List<UpmsRoleSystem> selectUpmsRoleSystemByUpmsUserId(Integer userId) {
        List<UpmsRole> roles = selectUpmsRoleByUpmsUserId(userId);
        List<Integer> roleIds = new ArrayList<>();
        roles.forEach(role -> roleIds.add(role.getRoleId()));
        return upmsRoleSystemMapper.selectList(new EntityWrapper<UpmsRoleSystem>().in("role_id", roleIds));
    }

    @Override
    public List<UpmsUserSystem> selectUpmsUserSystemByUpmsUserId(Integer userId) {
        // 根据用户id获取所有个人系统权限(包含加减所有列表，需要前台做处理)
        EntityWrapper<UpmsUserSystem> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("user_id", userId);
        return userSystemMapper.selectList(entityWrapper);
    }

    /**
     * 根据用户id获取所拥有的权限
     *
     * @param upmsUserId
     * @return
     */
    @Override
    public List<UpmsUserPermission> selectUpmsUserPermissionByUpmsUserId(Integer upmsUserId) {
        List<UpmsUserPermission> upmsUserPermissions = upmsUserPermissionMapper
                .selectList(new EntityWrapper<UpmsUserPermission>().eq("user_id", upmsUserId));
        return upmsUserPermissions;
    }

    /**
     * 根据条件获取系统数据
     *
     * @param entityWrapper
     * @return
     */
    @Override
    public List<UpmsSystem> selectUpmsSystemByExample(EntityWrapper<UpmsSystem> entityWrapper) {
        return upmsSystemMapper.selectList(entityWrapper);
    }

    /**
     * 根据条件获取组织数据
     *
     * @param entityWrapper
     * @return
     */
    @Override
    public List<UpmsOrganization> selectUpmsOrganizationByExample(EntityWrapper<UpmsOrganization> entityWrapper) {
        return upmsOrganizationMapper.selectList(entityWrapper);
    }

    /**
     * 根据username获取UpmsUser
     *
     * @param username
     * @return
     */
    @Override
    @Cacheable(value = "zheng-upms-rpc-service-ehcache", key = "'selectUpmsUserByUsername_' + #username", unless = "#result == null")
    public UpmsUser selectUpmsUserByUsername(String username) {
        List<UpmsUser> upmsUsers = upmsUserMapper.selectList(new EntityWrapper<UpmsUser>().eq("username", username));
        if (null != upmsUsers && upmsUsers.size() > 0) {
            return upmsUsers.get(0);
        }
        return null;
    }


    /**
     * 根据username获取UpmsOrganization
     *
     * @param username
     * @return
     */
    @Override
    @Cacheable(value = "zheng-upms-rpc-service-ehcache", key = "'selectUpmsOrganizationByUsername_' + #username", unless = "#result == null")
    public UpmsOrganization selectUpmsOrganizationByUsername(String username) {
        UpmsUser upmsUser = selectUpmsUserByUsername(username);
        if (upmsUser != null && upmsUser.getOrganizationId() != null) {
            return upmsOrganizationMapper.selectById(upmsUser.getOrganizationId());
        }
        return null;
    }



    /**
     * 获取组织（部门）tree
     *
     * @param isUser 是否有用户
     * @return
     */
    @Cacheable(cacheNames = "zheng-upms-rpc-service-ehcache", key = "'selectUpmsOrganizationAndUserTree' +#username+#isUser")
    public JSONArray selectUpmsOrganizationAndUserTree(Boolean isUser, String username) {
        Wrapper<UpmsOrganization> entityWrapper = new EntityWrapper<>();
        if (StringUtils.isNotBlank(username)) {
            entityWrapper = dataScopeFilter(entityWrapper, username);
        }
        List<UpmsOrganization> organizations = upmsOrganizationMapper.selectList(entityWrapper);
        JSONArray treeArray = new JSONArray();
        UpmsOrganization rootOrganization = new UpmsOrganization();
        for (UpmsOrganization organization : organizations) {
            JSONObject treeNode = new JSONObject();
            treeNode.put("id", organization.getOrganizationId());
            treeNode.put("nodeId", "organizationId" + organization.getOrganizationId());
            Integer pid = organization.getPid();
            if (pid != null) {
                treeNode.put("pId", organization.getPid());
                treeNode.put("pNodeId", "organizationId" + organization.getPid());
            }
            treeNode.put("path", organization.getPath() + organization.getOrganizationId());
            treeNode.put("name", organization.getName());
            treeArray.add(treeNode);
            if (organization.getPid() == 0) {
                rootOrganization = organization;
            }
        }
        if (isUser) {
            EntityWrapper<UpmsUser> userEntityWrapper = new EntityWrapper<>();
            userEntityWrapper.where("locked=" + 0);
            List<UpmsUser> users = upmsUserMapper.selectList(userEntityWrapper);
            for (UpmsUser user : users) {
                JSONObject treeNode = new JSONObject();
                treeNode.put("id", user.getUserId());
                treeNode.put("nodeId", "userId" + user.getUserId());
                Integer organizationId = user.getOrganizationId();
                if (null != organizationId) {
                    treeNode.put("pId", organizationId);
                    treeNode.put("pNodeId", "organizationId" + organizationId);
                } else if (null != rootOrganization.getPid()) {
                    treeNode.put("pId", rootOrganization.getOrganizationId());
                    treeNode.put("pNodeId", "organizationId" + rootOrganization.getOrganizationId());
                }
                treeNode.put("name", user.getRealname());
                treeNode.put("isUser", true);
                treeArray.add(treeNode);
            }
        }
        return treeArray;
    }


    @Override
    @CacheEvict(value = "zheng-upms-rpc-service-ehcache",allEntries = true)
    public void evictUpmsServiceCache() {

    }

    /**
     * 写入操作日志
     *
     * @param record
     * @return
     */
    @Override
    public int insertUpmsLogSelective(UpmsLog record) {
        return upmsLogMapper.insert(record);
    }

    /**
     * 数据权限过滤
     *
     * @param wrapper
     * @param username
     * @return
     */
    @Override
    public Wrapper dataScopeFilter(Wrapper wrapper, String username) {
        UpmsUser user = selectUpmsUserByUsername(username);
        return dataScopeFilter(wrapper, user);
    }

    /**
     * 数据权限过滤
     *
     * @param wrapper
     * @param user
     * @return
     */
    @Override
    public Wrapper dataScopeFilter(Wrapper wrapper, UpmsUser user) {
        List<UpmsRole> roles = selectUpmsRoleByUpmsUserIdByCache(user.getUserId());
        Integer dataScopeInteger = UpmsRole.DATA_SCOPE_SELF;
        List<UpmsRole> customScopeRole = new ArrayList<>();
        //获取角色最高权限
        for (UpmsRole role : roles) {
            if (role.getDataScope() == UpmsRole.DATA_SCOPE_CUSTOM) {
                customScopeRole.add(role);
                continue;
            }
            if (role.getDataScope() < dataScopeInteger) {
                dataScopeInteger = role.getDataScope();
            }
        }
        //具有所有权限
        if (dataScopeInteger == UpmsRole.DATA_SCOPE_ALL) {
            return wrapper;
        }

        wrapper.andNew();
        if (dataScopeInteger == UpmsRole.DATA_SCOPE_OFFICE_AND_CHILD) {
            UpmsOrganization userOrg = upmsOrganizationMapper.selectById(user.getOrganizationId());
            List<UpmsOrganization> childrenOrg = upmsOrganizationMapper.selectList(
                    new EntityWrapper<UpmsOrganization>().like("path", userOrg.getPath() + userOrg.getOrganizationId() + ","));
            List<Integer> orgIds = childrenOrg.stream().map(org -> org.getOrganizationId()).collect(Collectors.toList());
            orgIds.add(userOrg.getOrganizationId());
            wrapper.in("corganization", orgIds);
        } else if (dataScopeInteger == UpmsRole.DATA_SCOPE_OFFICE) {
            wrapper.eq("corganization", user.getOrganizationId());
        } else if (dataScopeInteger == UpmsRole.DATA_SCOPE_SELF) {
            wrapper.eq("cuser", user.getUserId());
        }

        if (customScopeRole.size() > 0) {
            Set<Integer> orgIdSet = new HashSet<>();
            for (UpmsRole role : customScopeRole) {
                Wrapper<UpmsRoleOrganization> roleOrgEntityWrapper = new EntityWrapper<>();
                roleOrgEntityWrapper.eq("roleId", role.getRoleId());
                List<UpmsRoleOrganization> roleOrgs = upmsRoleOrganizationService.selectList(roleOrgEntityWrapper);
                orgIdSet.addAll(roleOrgs.stream().map(upmsRoleOrganization -> upmsRoleOrganization.getOrganizationId()).collect(Collectors.toSet()));
            }
            wrapper.or().in("corganization", orgIdSet);
        }
        return wrapper;
    }

    public String sqlDataScopeFilter(String username, String tableAlias, String userTableAlias) {
        UpmsUser upmsUser = selectUpmsUserByUsername(username);
        return sqlDataScopeFilter(upmsUser, tableAlias, userTableAlias);
    }

    public String sqlDataScopeFilter(UpmsUser user, String tableAlias, String userTableAlias) {
        StringBuilder sql = new StringBuilder("");
        List<UpmsRole> roles = selectUpmsRoleByUpmsUserIdByCache(user.getUserId());
        Integer dataScopeInteger = UpmsRole.DATA_SCOPE_SELF;
        List<UpmsRole> customScopeRole = new ArrayList<>();
        //获取角色最高权限
        for (UpmsRole role : roles) {
            if (role.getDataScope() == UpmsRole.DATA_SCOPE_CUSTOM) {
                customScopeRole.add(role);
                continue;
            }
            if (role.getDataScope() < dataScopeInteger) {
                dataScopeInteger = role.getDataScope();
            }
        }
        if (dataScopeInteger == UpmsRole.DATA_SCOPE_ALL) {
            return sql.toString();
        }
        if (dataScopeInteger == UpmsRole.DATA_SCOPE_OFFICE_AND_CHILD) {
            UpmsOrganization userOrg = upmsOrganizationMapper.selectById(user.getOrganizationId());
            List<UpmsOrganization> childrenOrg = upmsOrganizationMapper.selectList(
                    new EntityWrapper<UpmsOrganization>().like("path", userOrg.getPath() + userOrg.getOrganizationId() + ","));
            List<Integer> orgIds = childrenOrg.stream().map(org -> org.getOrganizationId()).collect(Collectors.toList());
            orgIds.add(userOrg.getOrganizationId());
            sql.append("and ");
            sql.append(tableAlias);
            sql.append(".corganization in(");
            for (int i = 0, size = orgIds.size(); i < size; i++) {
                sql.append(orgIds.get(i));
                if (i != size - 1) {
                    sql.append(",");
                }
            }
            sql.append(")");
        } else if (dataScopeInteger == UpmsRole.DATA_SCOPE_OFFICE) {
            sql.append("and ");
            sql.append(tableAlias);
            sql.append(".corganization=");
            sql.append(user.getOrganizationId());
        } else if (dataScopeInteger == UpmsRole.DATA_SCOPE_SELF) {
            sql.append("and ");
            sql.append(tableAlias);
            sql.append(".cuser=");
            sql.append(user.getUserId());
        }

        if (customScopeRole.size() > 0) {
            Set<Integer> orgIdSet = new HashSet<>();
            for (UpmsRole role : customScopeRole) {
                Wrapper<UpmsRoleOrganization> roleOrgEntityWrapper = new EntityWrapper<>();
                roleOrgEntityWrapper.eq("roleId", role.getRoleId());
                List<UpmsRoleOrganization> roleOrgs = upmsRoleOrganizationService.selectList(roleOrgEntityWrapper);
                orgIdSet.addAll(roleOrgs.stream().map(upmsRoleOrganization -> upmsRoleOrganization.getOrganizationId()).collect(Collectors.toSet()));
            }
            sql.append("and ");
            sql.append(tableAlias);
            sql.append(".corganization in(");
            Iterator<Integer> iterator = orgIdSet.iterator();
            while (iterator.hasNext()) {
                Integer orgId = iterator.next();
                sql.append(orgId);
                if (iterator.hasNext()) {
                    sql.append(",");
                }
            }
            sql.append(")");
        }
        return sql.toString();
    }
}